/**
 * Copyright (c) 2012-2014 All Rights Reserved.
 */
package com.easy.framwork.utils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.easy.framwork.exceptions.ConvertException;
import com.easy.framwork.exceptions.IllegalArgException;
import com.easy.framwork.exceptions.ReflectException;
import com.easy.framwork.utils.bean.PropertyDescriptorsCache;

/**
 * 反射工具类
 * 
 * @author wy
 * @version v 0.1 2014-1-4 上午10:31:28 wy Exp $
 */
public class ReflectUtils {

    private final static Logger log = LoggerFactory.getLogger(ReflectUtils.class);

    /**
     * 实例一个对象
     * 
     * @param clazz
     * @return
     */
    public static <T> T newInstance(Class<T> clazz) {
        try {
            return clazz.newInstance();
        }
        catch (InstantiationException e) {
            log.error("instantiation class {} error,:{}", clazz, e);
            throw new ReflectException("获取构造方法出错");
        }
        catch (IllegalAccessException e) {
            log.error("illegal access for instance class {} error,:{}", clazz, e);
            throw new ReflectException("获取构造方法出错");
        }
    }

    /**
     * 实例一个对象
     * 
     * @param clazz
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T newInstance(Class<T> clazz, Object[] params) {

        int length = params == null ? 0 : params.length;
        if (length == 0) {
            return newInstance(clazz);
        }
        Class<?>[] parameterTypes = new Class<?>[length];
        int i = 0;
        for (Object param : params) {
            parameterTypes[i] = param.getClass();
        }
        try {
            Constructor<?> c = clazz.getConstructor(parameterTypes);
            if (c != null) {
                if (!Modifier.isPublic(c.getModifiers())
                    || !Modifier.isPublic(c.getDeclaringClass().getModifiers())) {
                    return null;
                }
                c.setAccessible(true);
                return ((T) c.newInstance(params));
            }
        }
        catch (Exception e) {
            log.error("获取class:{}的构造方法:({})出错",
                new Object[] { clazz.getName(), StringUtils.join(parameterTypes, ","), e });
            throw new ReflectException("获取构造方法出错");
        }
        return null;
    }

    /**
     * 转换
     * 
     * @param clazz
     * @param params
     * @return
     */
    public static <T> T newInstanceForConvertParam(Class<T> clazz, String[] params) {

        int length = params == null ? 0 : params.length;
        if (length == 0) {
            return newInstance(clazz);
        }

        try {
            return newInstance(clazz, params);
        }
        catch (Exception e) {
            //忽略 上面已经记录了，此时说明下面需要转换参数
        }

        Constructor<?>[] constructors = clazz.getConstructors();

        con: for (Constructor<?> constructor : constructors) {
            if (constructor.getParameterTypes().length != length) {
                continue;
            }
            Class<?>[] paramTypes = constructor.getParameterTypes();
            Object[] conParams = new Object[paramTypes.length];
            for (int i = 0; i < params.length; i++) {
                try {
                    conParams[i] = BeanUtils.convert(params[i], paramTypes[i]);
                }
                catch (Exception e) {
                    continue con;
                }
            }
            return newInstance(clazz, conParams);
        }
        return null;
    }

    /**
     * 
     * 
     * @param className
     * @return
     */
    public static Class<?> forName(String className) {
        try {
            return Class.forName(className);
        }
        catch (ClassNotFoundException e) {
            log.error("class {} not found:{}", className, e);
            throw new ReflectException("class" + className + "not found");
        }
    }

    /**
     * 写入值
     * 
     * @param obj
     * @param property
     * @param s
     */
    public static void writeProperty(Object obj, String property, String s) {
        if (obj == null || StringUtils.isBlank(property)) {
            throw new IllegalArgException("对象和属性都不能为空");
        }
        PropertyDescriptor pd = PropertyDescriptorsCache.forClass(obj.getClass())
            .getPropertyDescriptor(property);
        if (pd == null) {
            throw new ReflectException("从" + obj.getClass() + "中找不到属性" + property + "");
        } else if (pd.getWriteMethod() == null) {
            throw new ReflectException("从" + obj.getClass() + "中找不到属性" + property + "的set方法");
        }
        Object value = BeanUtils.convert(s, pd.getWriteMethod().getParameterTypes()[0]);
        try {
            pd.getWriteMethod().invoke(obj, value);
        }
        catch (Exception e) {
            log.warn("执行{}#{}的属性写入异常", new Object[] { obj.getClass(), property, e });
            throw new ConvertException("写入" + obj.getClass() + "中的属性" + property + "异常");
        }

    }
}
